#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define LISTEN_PORT 8889
#define BACKLOG 13                      //最大排队个数
int main(int argc, char **argv)
{
       	int rv = -1;
	int listen_fd, client_fd = -1;
	struct sockaddr_in serv_addr;          //定义该结构体用来存放服务器地址
	struct sockaddr_in cli_addr;           //定义该结构体用来存放客户端地址
	socklen_t cliaddr_len;          //accept需要用到
	char buf[1024];                         //读取字符串
	listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(listen_fd < 0 )
	{
		printf("create socket failure: %s\n", strerror(errno));
		return -1;                      //为什么要有返回值？为什么要返回-1而不是0？如果返回值能终止程序运行，那不用关闭文件吗？（在客户端代码:与goto到关闭文件处）(已解决)
	}
	printf("socket create fd[%d]\n", listen_fd);
	memset(&serv_addr, 0, sizeof(serv_addr));           //初始化服务器地址结构体
	serv_addr.sin_family = AF_INET;                     //定义服务器协议：ipv4
	serv_addr.sin_port = htons(LISTEN_PORT);            //定义服务器监听端口：8889；用htons把主机字节序转换成网络字节序
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);      //定义服务器监听的地址：全部；用htonl把主机字节序转换成网络字节序
	if( bind(listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0 ) //强制类型转化：把sockaddr_in类型的结构体转换成sockeaddr类型的结构体
	{
		printf("create socket failure: %s\n", strerror(errno));
		return -2;
	}
	printf("socket[%d] bind on port[%d] for all IP address ok\n", listen_fd, LISTEN_PORT);
	listen(listen_fd, BACKLOG);
	while(1)
	{
		//printf("\nStart waiting and accept new client connect...\n", listen_fd);

		printf("\nStart waiting and accept new client connect...\n");
		client_fd = accept(listen_fd, (struct sockaddr*)&cli_addr, &cliaddr_len);//接受客户端连接，返回客户端文件描述符,应该用memset初始化cli_addr结构体更好

		if(client_fd < 0)
		{
			printf("accept new socket failure: %s\n", strerror(errno));
			return -2;
		}
		printf("Accept new client[%s:%d] with fd [%d]\n", inet_ntoa(cli_addr.sin_addr),
				ntohs(cli_addr.sin_port), client_fd);//inet_ntoa():将4字节的整型地址转换成点分十进制字符串；ntohs():将网络传过来的客户端端口转换成本机字节序
		memset(buf, 0, sizeof(buf));
		if( (rv=read(client_fd, buf, sizeof(buf))) < 0)
		{
			printf("Read data from client socket[%d] failure: %s\n", client_fd, strerror(errno));
			close(client_fd);
			continue;
		}
		else if( rv == 0 )
		{
			printf("client socket[%d] disconnected\n", client_fd);
			close(client_fd);
			continue;
		}
		printf("read %d bytes data from client[%d] and echo it back: '%s'\n", rv, client_fd, buf);
		if( write(client_fd, buf, rv) < 0 )
		{
			printf("Write %d bytes data back to client[%d] failure: %s\n", rv, client_fd,strerror(errno));
			close(client_fd);
		}
		sleep(1);
		close(client_fd);
	}
	close(listen_fd);
}

